package com.mobile.service.impl.system;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.github.pagehelper.PageInfo;
import com.mobile.service.dao.DaoSupport;
import com.mobile.service.dto.AuthDTO;
import com.mobile.service.dto.UserDTO;
import com.mobile.service.dto.UserQueryDTO;
import com.mobile.service.inter.system.FunctionService;
import com.mobile.service.inter.system.OrganizationService;
import com.mobile.service.inter.system.RoleService;
import com.mobile.service.inter.system.UserService;
import com.mobile.service.util.PageUtils;
import com.mobile.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import redis.clients.jedis.Jedis;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户信息管理Service实现
 *
 * @author Administrator
 * @version 0.1 2021-01-15 初版
 */
@Service("userService")
@Transactional
public class UserServiceImpl implements UserService {
    @Resource(name = "daoSupport")
    private DaoSupport dao;
    @Autowired
    private RoleService roleService;
    @Autowired
    private OrganizationService organizationService;

    @Autowired
    FunctionService functionService;

    /**
     * 根据账号获取用户信息
     *
     * @param userCode 用户账号
     */
    @Override
    public PageData getUserByCode(String userCode) throws Exception {
        return (PageData) dao.findForObject("UserMapper.getUserByCode", userCode);
    }

    /**
     * 根据手机号获取用户信息
     *
     * @param phone 手机号
     * @return
     * @throws Exception
     */
    @Override
    public PageData getUserByPhone(String phone) throws Exception {
        return (PageData) dao.findForObject("UserMapper.getUserByPhone", phone);
    }


    /**
     * 修改密码
     *
     * @param pd
     * @return
     * @throws Exception
     */
    @Override
    public int updatePassword(PageData pd) throws Exception {
        pd.put("passwd", EncryptUtil.encrypt(pd.getString("passwd").trim() + pd.getString("secret_key")));
        return (int) dao.update("UserMapper.updatePassword", pd);
    }


    /**
     * 修改登录时间
     *
     * @param pd
     * @return
     * @throws Exception
     */
    @Override
    public int updateUser(PageData pd) throws Exception {
       return (int) dao.update("UserMapper.updateUserLoginTime", pd);
    }

    /**
     * 用户列表查询（分页）
     */
    @Override
    public PageResult<UserDTO> getUserListPage(UserQueryDTO userQueryDTO, PageData user) throws Exception {
        Integer organizationId = (Integer) user.get("organization_id");
        //获取用户角色代号（admin:平台运维  manager:总经理  market:市场部）
        String roleCode = user.getString("role_code");

        //平台运维和总经理能看到所有用户，其他部门角色只能看到本部门用户
        if(!Const.ROLE_CODE_ADMIN.equals(roleCode)) {
           userQueryDTO.setShowLeftTree(false);
            userQueryDTO.setOrganizationId(organizationId.toString());
        }else{
            userQueryDTO.setShowLeftTree(true);
        }

        //存在组织检索条件时,获取该组织机构以及下级所有机构的人员
        if (Optional.ofNullable(userQueryDTO.getOrganizationId()).isPresent()) {
            String orgId = userQueryDTO.getOrganizationId().toString();
            StringBuffer orgIndex = new StringBuffer();
            orgIndex.append(orgId+",");
            //根据父组织机构分组
            Map<String,List<PageData>> orgs = organizationService.getOrganizationBySerch(null).stream().collect(Collectors.groupingBy(x->x.get("parentId").toString()));
            String str = jointOrg(orgId, orgs, orgIndex);
            userQueryDTO.setOrganizationId(str);
        }
        PageUtils.startPage(userQueryDTO);
        List<UserDTO> list = (List<UserDTO>) dao.findForList("UserMapper.userlistPage", userQueryDTO);
        return new PageResult<>(list).set("showLeftTree", userQueryDTO.getShowLeftTree());
    }

    /**
     * 递归获取下级组织
     */
    String jointOrg(String orgId, Map<String, List<PageData>> orgs,StringBuffer index) {
        if (Optional.ofNullable(orgs.get(orgId)).isPresent()) {
            for (PageData i : orgs.get(orgId)) {
                String childrenId = i.get("organizationId").toString();
                index.append(childrenId + ",");
                jointOrg(childrenId, orgs,index);
            }
        }
        return index.toString().substring(0,index.length()-1);
    }






    /**
     * 新增用户
     *
     * @param pds
     * @return
     * @throws Exception
     */
    @Override
    public Map<String, Object> addUser(List<PageData> pds) throws Exception {
        Map<String, Object> map = new HashMap<>();
        for (PageData pd : pds) {
            PageData pdUser = (PageData) pd.get("user");

            //验证该用户账号是否已经存在（包括逻辑删除的用户）
            List<PageData> departments = (List<PageData>) dao.findForList("MOrganizationMapper.selectOrganizationAndDepartment", null);
            PageData user = (PageData) dao.findForObject("UserMapper.getUserByCodeForDelete", pd.getString("userCode"));
            if (null != user) {
                map.put(Const.ACTION_RESULT, Const.ACTION_RESULT_FAILED);
                map.put(Const.ACTION_MESSAGE, MessageUtil.getMessage("E0004", "用户账号: "+pd.getString("userCode")));
                return map;
            }
            //验证该手机号是否已经存在
            PageData userPhone = this.getUserByPhone(pd.getString("mobilePhone"));
            if (null != userPhone) {
                map.put(Const.ACTION_RESULT, Const.ACTION_RESULT_FAILED);
                map.put(Const.ACTION_MESSAGE, MessageUtil.getMessage("E0004", "手机号: "+pd.getString("mobilePhone")));
                return map;
            }
            //验证组织架构
            String organization=pd.getString("organization");
            String department=pd.getString("department");
            PageData organ = departments.stream()
                    .filter(or ->
                            organization.equalsIgnoreCase(or.getString("organizationName")) &&
                                    department.equalsIgnoreCase(or.getString("deparmentName"))
                    ).findFirst().orElse(null);
            if(Objects.isNull(organ)) {
                map.put(Const.ACTION_RESULT, Const.ACTION_RESULT_FAILED);
                map.put(Const.ACTION_MESSAGE, MessageUtil.getMessage("I0020"));
                return map;
            }
            pd.put("organizationId", organ.get("organizationId"));
            String roleCode = (String) pdUser.get("role_code");
            String isAdmin = (String) pdUser.get("is_admin");
            //不是部门管理员，只能添加普通专员用户
            if ("0".equals(isAdmin)) {
                pd.put("isAdmin", "0");
            }

            //添加用户
            //设置初始密码：123456 + 4位随机密钥
            String secretKey = VCodeUtils.getStringRandom(4);
            pd.put("secretKey", secretKey);
            pd.put("userPassword", EncryptUtil.encrypt("123456" + secretKey));
        }

        dao.batchSave("UserMapper.addUserBatch", pds);

        //添加用户分配的权限
        List<PageData> userAuthList = new ArrayList<>();
        //获取所有功能权限树
        List<PageData> authTree = roleService.getAuthTree();
        pds.forEach(pd->{
            String createUser = pd.getString("createUser");
            String userCode = pd.getString("userCode");
            Integer roleId = Integer.valueOf(pd.get("userRole").toString());
            //获取该用户分配的权限
            JSONArray selectAuth = JSON.parseArray(pd.getString("selectAuth"));
            //为用户分配权限
            this.userAuthRelation(authTree, roleId, userCode, createUser, userAuthList, selectAuth);
        });

        dao.batchSave("UserMapper.addUserAuth", userAuthList);

        map.put(Const.ACTION_RESULT, Const.ACTION_RESULT_SUCCESS);
        map.put(Const.ACTION_MESSAGE, MessageUtil.getMessage("I0011"));
        return map;
    }

    /**
     * 修改用户及分配的权限
     *
     * @param pd
     * @return
     */
    @Override
    public Map<String, Object> updateUserWithAuth(PageData pd, Jedis jedis) throws Exception {
        Map<String, Object> map = new HashMap<>();
        String userCode = pd.getString("userCode");
        String createUser = pd.getString("createUser");
        Object jobNo = pd.get("jobNo");
        pd.put("updateTatetime", new Date());
        PageData pdUser = (PageData) pd.get("user");

        PageData data = (PageData) dao.findForObject("UserMapper.getUserByCode", userCode);
        if (Objects.isNull(data)) {
            map.put(Const.ACTION_RESULT, Const.ACTION_RESULT_FAILED);
            map.put(Const.ACTION_MESSAGE, MessageUtil.getMessage("E0001"));
            return map;
        }

        //验证修改的手机号是否存在,手机号相同但是用户code不同，代表手机号重复
        PageData userPhone = this.getUserByPhone(pd.getString("mobilePhone"));
        if (null != userPhone && !userCode.equals(userPhone.getString("user_code"))) {
            map.put(Const.ACTION_RESULT, Const.ACTION_RESULT_FAILED);
            map.put(Const.ACTION_MESSAGE, MessageUtil.getMessage("E0004", "该手机号"));
            return map;
        }

        String isAdmin = (String) pdUser.get("is_admin");
        //不是平台运维、总经理角色，也不是部门管理员，只能添加普通专员用户
        if ("0".equals(isAdmin)) {
            pd.put("isAdmin", "0");
        }


        //修改用户信息
        dao.update("UserMapper.updateUser", pd);

        //删除用户原来权限，重新分配
        dao.delete("UserMapper.deleteUserAuthByCode", userCode);
        Integer roleId = Integer.valueOf(pd.get("userRole").toString());
        List<PageData> userAuthList = new ArrayList<>();
        //获取所有功能权限树
        List<PageData> authTree = roleService.getAuthTree();
        //获取该用户分配的权限
        JSONArray selectAuth = JSON.parseArray(pd.getString("selectAuth"));
        //分配权限
        this.userAuthRelation(authTree, roleId, userCode, createUser, userAuthList, selectAuth);
        dao.batchSave("UserMapper.addUserAuth", userAuthList);
        //清除redis菜单权限信息
        PageData rfaPd = new PageData();
        rfaPd.put("userCode", userCode);
        List<String> rfaButtonFunctionList = functionService.getAuthDataByUserCode(rfaPd);
        jedis.hdel( Const.SESSION_menuList,userCode);
        jedis.hset( Const.SESSION_menuList,userCode,JSON.toJSONString(rfaButtonFunctionList));
        jedis.hdel( Const.SESSION_allmenuList,userCode);
        map.put(Const.ACTION_RESULT, Const.ACTION_RESULT_SUCCESS);
        map.put(Const.ACTION_MESSAGE, MessageUtil.getMessage("I0009"));
        return map;
    }

    /**
     * 启用/禁用账户
     * isLocked：账户锁定标志（0：禁用  1：启用  2：删除）
     *
     * @param pd
     */
    @Override
    public void lockedUser(PageData pd) throws Exception {
        dao.update("UserMapper.updateUser", pd);
    }

    @Override
    public PageData getLoginUserInfo(String userCode) throws Exception {
        return (PageData) dao.findForObject("UserMapper.getUserByCode", userCode);
    }



    /**
     * 修改用户信息
     * @param pd
     * @return
     * @throws Exception
     */
    @Override
    public int updateUserInfo(PageData pd) throws Exception {
        return (int) dao.update("UserMapper.updateUser", pd);
    }

    /**
     * 删除用户
     *（逻辑删除：is_locked='2'为删除）
     * 同时注意手机号要置空
     * @param pd
     * @throws Exception
     */
    @Override
    public void removeUser(PageData pd) throws Exception {
        pd.put("isLocked", "2");
        pd.put("mobilePhone", "");
        dao.update("UserMapper.updateUser", pd);
        //删除用户分配权限
        dao.delete("UserMapper.deleteUserAuthByCode", pd.getString("userCode"));
    }

    /**
     * 根据用户账号获取用户信息和分配的权限
     *
     * @param userCode
     * @return
     */
    @Override
    public Map<String, Object> getUserWithAuthByCode(String userCode) throws Exception {
        Map<String, Object> map = new HashMap<>();
        PageData user = (PageData) dao.findForObject("UserMapper.getUserByCode", userCode);
        map.put("data", user);

        //查询该用户分配的权限
        map.put("auths", this.getUserAuthByUserCode(userCode));

        map.put(Const.ACTION_RESULT, Const.ACTION_RESULT_SUCCESS);
        return map;
    }

    /**
     * 查询出该角色分配的菜单权限
     */
    @Override
    public List<PageData> getMenuAuthByRole(Integer roleId) throws Exception {
        //查询该角色具有权限的最顶级父菜单
        List<PageData> parentMenu = (List<PageData>) dao.findForList("UserMapper.getParentMenuByRole", roleId);
        //根据父菜单ID查询该角色具有权限的子菜单
        getSubMenuAuthByRole(roleId, parentMenu);
        return parentMenu;
    }


    private List<PageData> getSubMenuAuthByRole(Integer roleId, List<PageData> menuList) throws Exception {
        for (PageData menu : menuList) {
            //父菜单ID
            Integer key = Integer.valueOf(menu.get("key").toString());
            PageData params = new PageData();
            params.put("roleId", roleId);
            params.put("parentId", key);

            //根据父菜单ID查询该角色具有权限的子菜单
            List<PageData> subMenuList = (List<PageData>) dao.findForList("UserMapper.getSubMenuByRole", params);
            if (subMenuList.isEmpty()) {
                String menuKey = menu.get("key").toString();
                String[] authIds = menu.getString("authIds").split(",");
                String[] authNames = menu.getString("authNames").split(",");
                List<PageData> children = new ArrayList<>();
                for (int i = 0; i < authIds.length; i++) {
                    PageData auth = new PageData();
                    auth.put("key", menuKey + "-" + authIds[i]);
                    auth.put("title", authNames[i]);
                    children.add(auth);
                }
                menu.put("children", children);
            } else {
                //递归获取该角色拥有权限的子菜单
                getSubMenuAuthByRole(roleId, subMenuList);
                menu.put("children", subMenuList);
            }
        }
        return menuList;
    }


    /**
     * 为用户分配功能权限
     */
    private void userAuthRelation(List<PageData> authTree, Integer roleId,
                                  String userCode, String createUser,
                                  List<PageData> userAuthList, JSONArray selectAuth) {
        for (Object menuObj : authTree) {
            PageData menu = (PageData) menuObj;
            List<PageData> subMenus = (List<PageData>) menu.get("children");
            if (null == subMenus || subMenus.isEmpty()) {
                String key = menu.getString("key");
                String[] split = key.split("-");
                String functionId = split[0];
                String authId = split[1];
                PageData userAuth = new PageData();
                userAuth.put("userCode", userCode);
                userAuth.put("roleId", roleId);
                userAuth.put("functionId", functionId);
                userAuth.put("authId", authId);
                String authCode=Optional.ofNullable(selectAuth).map(auth -> auth.contains(key) ? "1" : "0").orElse("1");
                userAuth.put("isAuth", authCode);
                userAuth.put("createUser", createUser);
                userAuth.put("updateUser", createUser);
                userAuthList.add(userAuth);
            } else {
                //递归分配权限
                userAuthRelation(subMenus, roleId, userCode, createUser, userAuthList, selectAuth);
            }
        }
    }

    /**
     * 查询出该用户分配的菜单权限
     * @param userCode
     * @return
     * @throws Exception
     */
    @Override
    public List<PageData> getMenuAuthByUser(String userCode) throws Exception {

        //查询该用户具有权限的最顶级父菜单
        List<PageData> parentMenu = (List<PageData>) dao.findForList("UserMapper.getParentMenuByUser", userCode);
        //根据父菜单ID查询该用户具有权限的子菜单
        getSubMenuAuthByUser(userCode, parentMenu);
        return parentMenu;
    }

    private List<PageData> getSubMenuAuthByUser(String userCode, List<PageData> menuList) throws Exception {
        for (PageData menu : menuList) {
            //父菜单ID
            Integer key = Integer.valueOf(menu.get("key").toString());
            PageData params = new PageData();
            params.put("userCode", userCode);
            params.put("parentId", key);

            //根据父菜单ID查询该用户具有权限的子菜单
            List<PageData> subMenuList = (List<PageData>) dao.findForList("UserMapper.getSubMenuByUser", params);
            if (subMenuList.isEmpty()) {
                String menuKey = menu.get("key").toString();
                String[] authIds = menu.getString("authIds").split(",");
                String[] authNames = menu.getString("authNames").split(",");
                List<PageData> children = new ArrayList<>();
                for (int i = 0; i < authIds.length; i++) {
                    PageData auth = new PageData();
                    auth.put("key", menuKey + "-" + authIds[i]);
                    auth.put("title", authNames[i]);
                    children.add(auth);
                }
                menu.put("children", children);
            } else {
                //递归获取该角色拥有权限的子菜单
                getSubMenuAuthByUser(userCode, subMenuList);
                menu.put("children", subMenuList);
            }
        }
        return menuList;
    }

    /**
     * 查询该用户具有的权限(‘菜单ID-权限ID’格式)
     * @param userCode
     * @return
     * @throws Exception
     */
    @Override
    public List<String> getUserAuthByUserCode(String userCode) throws Exception {
        return (List<String>) dao.findForList("UserMapper.getUserAuthByUserCode", userCode);
    }

    /**
     * 查询该角色具有的权限(‘菜单ID-权限ID’格式)
     * @param roleId
     * @return
     * @throws Exception
     */
    @Override
    public List<String> getRoleAuthByRoleId(Integer roleId) throws Exception {
        return (List<String>) dao.findForList("UserMapper.getRoleAuthByRoleId", roleId);
    }




    //树形结构递归获取组织机构列表
    List<PageData> organizationTreeList(List<PageData> organizationTreeList,Map<String,List<PageData>> treeMap,Map<String, List<PageData>> userMap) {
        organizationTreeList.forEach(pd->{
            List<PageData> list = Optional.ofNullable(treeMap.get(pd.get("organizationId").toString())).orElse(new ArrayList<>());
            List<PageData> userList = Optional.ofNullable(userMap.get(pd.get("organizationId").toString())).orElse(new ArrayList<>());
            list = organizationTreeList(list, treeMap,userMap);
            list.addAll(userList);
            pd.put("disabled", true);
            pd.put("children", list);
            pd.put("value", pd.get("organizationId").toString());
        });
        return organizationTreeList;
    }

}
